/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package algos;

import java.util.HashMap;
import model.Algorithm;

/**
 *
 * @author Administrator
 */
public class BinomialTreeModel extends Algorithm {

    private static final OptionType[] optionTypes = (new OptionType[]{OptionType.EUROPEAN_CALL, OptionType.EUROPEAN_PUT, OptionType.AMERICAN_CALL, OptionType.AMERICAN_PUT});
    private static final String algoName = "Binomial Tree";

    private int numIntervals;

    private double daltaT, r1per, disc, up, down, price_up, price_dn, cur_price;
    private double[] val;

    public BinomialTreeModel() {
        super(algoName, optionTypes, new double[]{0.0,0.0});
        //super.getExtraParameters().put("Intervals", 0.0);
    }

    public BinomialTreeModel(String companyTicker, double currentStockPrice, double strikePrice, double term, double volatility, double riskFreeRate, double[] extraParametersInput) {
        super(algoName, companyTicker, currentStockPrice, strikePrice, term, volatility, riskFreeRate, optionTypes, extraParametersInput);
        //super.getExtraParameters().put("Intervals", (double) numIntervals);
        
    }    
    
    @Override
    public void initExtraParameters(double[] extraParametersInput){
        super.getExtraParameters().put("Intervals", extraParametersInput[0]);
        this.numIntervals = ((Double)extraParametersInput[0]).intValue();
    }

    public void OptionPricing(int num) {
        val = new double[num];
    }

    private void newPars(double term, int numInterval, double rate, double volatility) {
        numIntervals = numInterval;
        daltaT = term / (double) numIntervals;
        r1per = 1.0 + rate * daltaT;
        disc = 1.0 / r1per;
        up = r1per + volatility * Math.sqrt(daltaT);
        down = r1per - volatility * Math.sqrt(daltaT);
        price_up = disc * 0.5;
        price_dn = disc * 0.5;
    }

    public double calculateCallPrice() {
        OptionPricing(5001);
        int i, j; // i and j indicate the current node in the binomial tree
        double price;
        // calulate the up and down parameters
        newPars(super.getTerm(), numIntervals, super.getRiskFreeRate(), super.getVolatility());

        // initialize terminal payoffs: i is the number of up moves over the whole life
        for (i = 0; i <= numIntervals; i++) {
            price = super.getCurrentStockPrice() * Math.pow(up, (double) i) * Math.pow(down, (double) (numIntervals - i));
            val[i] = Math.max(price - super.getStrikePrice(), (double) 0.0);
        }

        for (j = 0; j < numIntervals; j++) {
            for (i = 0; i < numIntervals; i++) {
                val[i] = price_dn * val[i] + price_up * val[i + 1];
            }
        }

        return (val[0]);
    }

    public double calculatePutPrice() {

        OptionPricing(5001);
        int i, j; // i and j indicate the current node in the binomial tree
        double price;
        // calulate the up and down parameters
        newPars(super.getTerm(), numIntervals, super.getRiskFreeRate(), super.getVolatility());

        // initialize terminal payoffs: i is the number of up moves over the whole life
        for (i = 0; i <= numIntervals; i++) {
            price = super.getCurrentStockPrice() * Math.pow(up, (double) i) * Math.pow(down, (double) (numIntervals - i));
            val[i] = Math.max(super.getStrikePrice() - price, (double) 0.0);
        }

        for (j = 0; j < numIntervals; j++) {
            for (i = 0; i < numIntervals; i++) {
                val[i] = price_dn * val[i] + price_up * val[i + 1];
            }
        }

        return (val[0]);
    }

    public static void main(String[] args) {
        Algorithm a = new BinomialTreeModel("A", 50, 40, 0.4, 0.4, 0.1, new double[]{5.0});
        System.out.println(a.calculateCallPrice());
        System.out.println(a.calculatePutPrice());
    }
}
